package com.xujl.reflectcontainer;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.support.annotation.IntRange;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;

/**
 * <pre>
 *     @author : xujl
 *     e-mail : 597355068@qq.com
 *     time   : 2018/10/16
 *     desc   : 倒影布局
 *     version: 1.0
 * </pre>
 */
public class ReflectContainer extends FrameLayout {
    private final static String TAG = "ReflectContainer";
    /**
     * 倒影高度缩放,默认不缩放
     */
    private float mReflectionScale = 1f;
    /**
     * 倒影与原图间隔
     */
    private float mReflectionSpace = 10;
    /**
     * 倒影比例
     */
    private float mReflectionHeightRatio = 1f;
    private float mReflectionStartTransparency = 0.7f;
    private float mReflectionEndTransparency = 0.2f;

    private final Paint mDarkPaint = new Paint();
    private final Paint mReflectionPaint = new Paint();
    private Shader mShader;
    private Matrix mMatrix = new Matrix();

    public ReflectContainer (Context context) {
        this(context, null);
    }

    public ReflectContainer (Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ReflectContainer (Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setWillNotDraw(false);
        initAttrs(attrs);
        mShader = new LinearGradient(0, 0, 0, 1,
                transparencyToInt(mReflectionStartTransparency),
                transparencyToInt(mReflectionEndTransparency), Shader.TileMode.MIRROR);
        mDarkPaint.setColor(0x98000000);
        mReflectionPaint.setShader(mShader);
        mReflectionPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mMatrix.preScale(1, -1);
    }


    private void initAttrs (AttributeSet attrs) {
        if (attrs != null) {
            TypedArray typeArray =
                    getContext().obtainStyledAttributes(attrs, R.styleable.ReflectContainer);
            mReflectionHeightRatio =
                    typeArray.getFloat(R.styleable.ReflectContainer_reflectionHeightRatio, 1f);
            mReflectionScale = typeArray.getFloat(R.styleable.ReflectContainer_reflectionScale, 1f);
            mReflectionStartTransparency = typeArray.getFloat(R.styleable.ReflectContainer_reflectionStartTransparency, 0.7f);
            mReflectionEndTransparency = typeArray.getFloat(R.styleable.ReflectContainer_reflectionEndTransparency, 0.2f);
            mReflectionSpace = typeArray.getInt(R.styleable.ReflectContainer_reflectionSpace, 10);
            typeArray.recycle();
        }
    }


    @Override
    protected void onMeasure (int wspec, int hspec) {
        super.onMeasure(wspec, hspec);
        if (getChildCount() > 0) {
            View child = getChildAt(0);
            int childw = child.getMeasuredWidth();
            int childh = child.getMeasuredHeight();
            setMeasuredDimension(resolveSize(childw, wspec), resolveSize((int) (childh * (mReflectionHeightRatio + 1) + mReflectionSpace), hspec));
        }
    }

    @Override
    protected void onDraw (Canvas canvas) {
        long now = System.currentTimeMillis();
        if (getChildCount() > 0) {
            drawReflection(canvas);
        }
        long elapsed = System.currentTimeMillis() - now;
        Logger.e(TAG, "Drawing took " + elapsed + " ms");
    }

    private void drawReflection (Canvas canvas) {
        View child = getChildAt(0);
        child.setDrawingCacheEnabled(true);

        child.buildDrawingCache();
        int childw = child.getWidth();
        int childh = child.getHeight();
        int selfh = getHeight();
        int poolh = (int) (childh * mReflectionHeightRatio);
        //绘制倒影
        canvas.saveLayer(child.getLeft(), child.getBottom(), child.getRight(), child.getBottom() + getBottom(), null, Canvas.ALL_SAVE_FLAG);
        // Draw the flipped child.
        canvas.save();
        canvas.scale(1, -mReflectionScale);
        canvas.translate(0, -childh * (1 + 1 / mReflectionScale) - mReflectionSpace / mReflectionScale);
        //旋转角度
//        canvas.rotate(10,childw,poolh);
        child.draw(canvas);
        canvas.restore();

        mMatrix.setScale(1, poolh);
        mMatrix.postTranslate(0, childh + mReflectionSpace);
        mShader.setLocalMatrix(mMatrix);
        canvas.drawRect(0, childh + mReflectionSpace, childw, selfh, mReflectionPaint);
        //Apply the canvas layer.
        canvas.restore();
    }

    public void updateRefect () {
        postInvalidate();
    }

    public void setReflectionScale (float reflectionScale) {
        mReflectionScale = reflectionScale;
        updateRefect();
    }

    public void setReflectionSpace (float reflectionSpace) {
        mReflectionSpace = reflectionSpace;
        updateRefect();
    }

    public void setReflectionHeightRatio (float reflectionHeightRatio) {
        mReflectionHeightRatio = reflectionHeightRatio;
        updateRefect();
    }

    public void setReflectionStartTransparency (float reflectionStartTransparency) {
        mReflectionStartTransparency = reflectionStartTransparency;
        mShader = new LinearGradient(0, 0, 0, 1,
                transparencyToInt(mReflectionStartTransparency),
                transparencyToInt(mReflectionEndTransparency), Shader.TileMode.MIRROR);
        updateRefect();
    }

    public void setReflectionEndTransparency (float reflectionEndTransparency) {
        mReflectionEndTransparency = reflectionEndTransparency;
        mShader = new LinearGradient(0, 0, 0, 1,
                transparencyToInt(mReflectionStartTransparency),
                transparencyToInt(mReflectionEndTransparency), Shader.TileMode.MIRROR);
        updateRefect();
    }

    /**
     * 获取透明度颜色值
     *
     * @param ratio
     */
    private int transparencyToInt (float ratio) {
        if (ratio > 1f) {
            return 0xffffffff;
        }
        if (ratio < 0f) {
            return 0x00ffffff;
        }
        return argb((int) (255 * ratio), 255, 255, 255);
    }

    private int argb (
            @IntRange(from = 0, to = 255) int alpha,
            @IntRange(from = 0, to = 255) int red,
            @IntRange(from = 0, to = 255) int green,
            @IntRange(from = 0, to = 255) int blue) {
        return (alpha << 24) | (red << 16) | (green << 8) | blue;
    }
}
